#include "serialporthandle.h"

// 串口实现类
SerialportHandle::SerialportHandle(QObject *parent)
    :QSerialPort(parent)
{
    connect(this, &QSerialPort::readyRead, this, &SerialportHandle::onReadyRead);
    connect(this, &QSerialPort::errorOccurred, this, &SerialportHandle::onErrorOccurred);

    m_pRecursiveMutex = new QMutex(QMutex::Recursive);

    m_pThread = new QThread;
    this->moveToThread(m_pThread);
    m_pThread->start();
}

// 串口析构
SerialportHandle::~SerialportHandle()
{
}

// 判断是否打开
bool SerialportHandle::isOpened()
{
    return this->isOpen();
}

// 设置串口信息
void SerialportHandle::setSerialInfo(PSeriaPortInfo info)
{
    m_SerialInfo = info;
}

// 串口打开
bool SerialportHandle::onOpenPort(QString connName)
{
    QMutexLocker locker(m_pRecursiveMutex);
    if (connName != m_SerialInfo.name) return false;

    QSerialPort::BaudRate	_baudrate; // 波特率
    QSerialPort::Parity	    _Parity; // 校验位
    QSerialPort::DataBits	_databits; // 数据位
    QSerialPort::StopBits	_stopbits; // 停止位

    // 波特率
    _baudrate = (QSerialPort::BaudRate)m_SerialInfo.baudrate;
    // 数据位
    _databits = (QSerialPort::DataBits)m_SerialInfo.databits;

    // 校验位
    QMetaEnum metaParity = QMetaEnum::fromType<QSerialPort::Parity>();
    _Parity = (QSerialPort::Parity) metaParity.keyToValue(m_SerialInfo.parity.toStdString().c_str());

    // 停止位
    if (m_SerialInfo.stopbits == "1")
    {
        _stopbits = QSerialPort::StopBits::OneStop;
    }
    else if (m_SerialInfo.stopbits == "1.5")
    {
        _stopbits = QSerialPort::StopBits::OneAndHalfStop;
    }
    else if (m_SerialInfo.stopbits == "2")
    {
        _stopbits = QSerialPort::StopBits::TwoStop;
    }
    else
    {
        _stopbits = QSerialPort::StopBits::UnknownStopBits;
    }
    // 串口号
    this->setPortName(m_SerialInfo.comNO);

    // 打开串口
    if (this->open(QIODevice::ReadWrite))
    {
        this->setReadBufferSize(1024);
        if (!this->setBaudRate(_baudrate))		return false;
        if (!this->setDataBits(_databits))		return false;
        if (!this->setParity(_Parity))			return false;
        if (!this->setStopBits(_stopbits))		return false;
        if (!this->setFlowControl(QSerialPort::NoFlowControl)) 	return false;

        this->setFlowControl(QSerialPort::NoFlowControl);     //设置流控制

        qInfo() << QStringLiteral("串口[%1],端口[%2],波特率[%3],数据位[%4],校验位[%5],停止位[%6] 打开成功")
            .arg(m_SerialInfo.name)
            .arg(m_SerialInfo.comNO)
            .arg(m_SerialInfo.baudrate)
            .arg(m_SerialInfo.databits)
            .arg(m_SerialInfo.parity)
            .arg(m_SerialInfo.stopbits);

        return true;
    }
    return false;
}

// 串口关闭
void SerialportHandle::onClosePort(QString connName)
{
    QMutexLocker locker(m_pRecursiveMutex);
    if (connName != m_SerialInfo.name) return ;

    if (isOpened())
    {
        this->clear();
        this->close();
        qInfo() << QStringLiteral("串口[%1],端口[%2],波特率[%3],数据位[%4],校验位[%5],停止位[%6] 关闭成功")
            .arg(m_SerialInfo.name)
            .arg(m_SerialInfo.comNO)
            .arg(m_SerialInfo.baudrate)
            .arg(m_SerialInfo.databits)
            .arg(m_SerialInfo.parity)
            .arg(m_SerialInfo.stopbits);

    }
}

// 数据发送
bool SerialportHandle::onWriteData(QString connName, QString strSend, bool isHex, int msTimeout, bool bAsync)
{
    QMutexLocker locker(m_pRecursiveMutex);

    if (connName != m_SerialInfo.name) return false;
    this->readAll();	//发送之前，清空接收缓冲

    if (isHex)
    {
        QByteArray hexBuf = QStringHexToByteArrayHex(strSend);
        this->write(hexBuf);
    }
    else
    {
        QByteArray sendByteArray = strSend.toLocal8Bit();		//必须分开写
        char* data = new char[sendByteArray.size() + 1];
        strcpy_s(data, sendByteArray.size() + 1, sendByteArray.data());

        this->write(data);

        delete data;
        data = NULL;
    }
    bool bWriteSucceed = true;
    if (!bAsync)
    {
        bWriteSucceed = this->waitForBytesWritten(msTimeout);
    }
    return bWriteSucceed;
}

// 数据接收-是否超时
bool SerialportHandle::onReadData(QString connName, QString& strRecv, int msTimeout)
{
    QMutexLocker locker(m_pRecursiveMutex);
    if (connName != m_SerialInfo.name) return false;

    bool rtn = true;
    rtn = wait_result_sync(msTimeout);
    if (rtn)
    {
        strRecv = m_strRecv;
        m_strRecv.clear();
    }

    if (strRecv.isEmpty())
    {
        return false;
    }
    return true;

}

// 数据发送接收
bool SerialportHandle::onWriteReadData(QString connName, QString strSend, QString& strRecv, bool isHex, int msTimeout)
{
    //异步写入，同步接收
    onWriteData(connName, strSend, isHex, msTimeout, true);
    return onReadData(connName, strRecv, msTimeout);
}

// 数据接收
void SerialportHandle::onReadyRead()
{
    m_recevieTimer.reset(new QTimer);
    connect(m_recevieTimer.data(), &QTimer::timeout, this, &SerialportHandle::on_receive_allData);
    m_recevieTimer.data()->start(100);
    QByteArray byteArray = this->readAll();
    if (m_bRecvHexData){
//        QString hexString = byteArray.toHex();
        QString hexString= ByteArrayToHexString(byteArray);
        QByteArray readComData = hexString.toLatin1();
        m_temporayRecvData.append(readComData);
    } else {
        m_temporayRecvData.append(byteArray);
    }
}

// 接收数据相应
void SerialportHandle::on_receive_allData()
{
    m_recevieTimer.data()->stop();
    m_strRecv = m_temporayRecvData;
    m_temporayRecvData.clear();
    emit sig_finished();
    emit sig_recvMsg(m_SerialInfo.name, m_strRecv);
}

// 验证是否超时
bool SerialportHandle::wait_result_sync(int msTimeout)
{
    bool ret = false;
    QTimer timer;
    QEventLoop eventLoop;
    connect(&timer, &QTimer::timeout, &eventLoop, &QEventLoop::quit, Qt::DirectConnection);
    connect(this, &SerialportHandle::sig_finished, &eventLoop, &QEventLoop::quit, Qt::DirectConnection);

    timer.start(msTimeout);
    eventLoop.exec();
    if (!timer.isActive())
    {
        qCritical() << QStringLiteral("串口[%1],端口[%2],波特率[%3],数据位[%4],校验位[%5],停止位[%6] 超时")
            .arg(m_SerialInfo.name)
            .arg(m_SerialInfo.comNO)
            .arg(m_SerialInfo.baudrate)
            .arg(m_SerialInfo.databits)
            .arg(m_SerialInfo.parity)
            .arg(m_SerialInfo.stopbits);
        ret = false;
    }
    else
    {
        timer.stop();
        ret = true;
    }

    return ret;
}

// 串口错误
void SerialportHandle::onErrorOccurred(QSerialPort::SerialPortError error)
{
    if (error == QSerialPort::ResourceError)
    {
        qWarning() << QStringLiteral("串口[%1],端口[%2],波特率[%3],数据位[%4],校验位[%5],停止位[%6] 发生错误:%7")
            .arg(m_SerialInfo.name)
            .arg(m_SerialInfo.comNO)
            .arg(m_SerialInfo.baudrate)
            .arg(m_SerialInfo.databits)
            .arg(m_SerialInfo.parity)
            .arg(m_SerialInfo.stopbits)
            .arg(this->errorString());
    }
}

// 转换16进制
QByteArray SerialportHandle::QStringHexToByteArrayHex(QString src)
{
    return QByteArray::fromHex(src.toLatin1());
}

// 转16进制
QString SerialportHandle::ByteArrayToHexString(QByteArray data){
    QString ret(data.toHex().toUpper());
    int len = ret.length()/2;
    for(int i=1;i<len;i++)
    {
        ret.insert(2*i+i-1," ");
    }

    return ret;
}
